<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Inheritance No.1 Class Inheritance</title>
</head>
<body>
    类式继承
</body>
<script>
    // 是时候到我们传说的继承了
    // 就像人类祖辈相承成就如今人类文明一样
    // 代码也是能做到继承的。如C里的base等关键字。当然，js是啥都没有的，哈哈哈
    // 但是js也能做到继承
    // 先了解下继承，继承的特点，父母讲一些基因传递给子女，当然父母也有自己的特性，子女也有自己独有的地方
    // 接下来我们就进行继承的实现

    // 1 类式继承 顾名思义，通过我们之前demo3学习的Class概念来完成继承

    //先写爸爸
    function Father(){
        this.name = '爸爸';
        this.age = 28;   //爸爸28岁
        this.sex = '男';
        this.body = ['172','70'];
        this.hand = {
            'wristPower' : 123,
            'handPower' : 123
        }
    }

    Father.drink =function(){   // 爸爸特有的行为?不对，这只是Father类的专有。。。
        console.log(this.name+"喝酒");
        return this.age; //一言不合喝酒的时候把年龄暴露了
    }

    Father.prototype.eat=function(){
        console.log(this.name+"吃饭");
        return this.sex+this.name;
    }

    //再来个儿子
    function Son(){
        this.name = '儿子';
        
        //下面这几项在测试如果这些属性不是父类的时，不存在所谓的公用引用问题，解开下面注释，缺点的显示是否就都不受影响了？
        //this.age = 2; //儿子2岁 儿子独有的属性
        // this.sex = '男';
        // this.body = ['172','70'];
        // this.hand = {
        //     'wristPower' : 123,
        //     'handPower' : 123
        // }        
    }
    //这是继承，这是继承，这是继承，重要的事情说三遍。
    //把儿子的原型复制一个父亲实例。
    //也就是我们说的儿子和爸爸的共性部分
    Son.prototype =new Father();
    //那儿子也有点自己的特性吧
    Son.prototype.drinkMilk=function(){
        console.log(this.name+"喝奶");
        return this.name;
    }

    // 这继承类咱们写完了，当然也有些不妥，当然不是所有爸爸都喝酒，也不是所有小孩2岁都不断奶，但就是个意思
    // 既然定义了类，我们就来给他实例化一下，看看是不是我们想要的
    var XiaoMing = new Son();  //著名的小明出场了，他是儿子
    var DaMing = new Father(); //再来个大明当爸爸，当然你要有性质，叫姚明也无所谓。

    /**********************下面是继承与否的测试语句******************************/

    //console.log(DaMing.drink()); //not a function
    console.log(DaMing.eat()); //爸爸吃饭（eat方法输出） 男爸爸（函数返回值）
   // console.log(XiaoMing.drink());  //not a function
    console.log(XiaoMing.eat()); // 儿子吃饭（eat方法中输出） 男儿子（函数返回值）
    console.log(XiaoMing.drinkMilk()); //儿子喝奶 （drinkMilk方法中输出） 儿子（函数返回值）

    //再来看看继承关系 instanceof我们已经在之前安全模式用过了，意思是是否为某个类的实例
    console.log(XiaoMing instanceof Son);  //显然是true
    console.log(XiaoMing instanceof Father); //也是true，变相证明Son的类继承了了Father类
    console.log(Son instanceof Father);  //fales XiaoMing都是他们的实例，只是侧面反应继承效果达到，但并不能从机理上就想为Son是Father的实例，因为根据语句我们也可以知道：
    console.log(Son.prototype instanceof Father); //true

    //感觉上，我们实现了继承效果了，但是实际上类式继承有2个很大的缺陷
    //1 如Father中的this.sex，由于在子类Son中并没有这个属性，所以这个属性成为了所有Son子类公用的一个类，那么：
    //一开始我以为说只要我一个子类实例改变了父类独有的属性，其他都会修改。。。结果并不是这样
    /***************************下面是关于类式继承缺点的测试******************************************/
    var XiaoHong = new Son();
    //先把小红小明打印出来看看
    console.log(XiaoHong);
    console.log(XiaoMing);

    XiaoHong.age = 18 //我要快快长大
    console.log(XiaoHong.age); //18
    console.log(XiaoMing.age); //28  

    XiaoHong.sex = '女' //人家是女孩子
    console.log(XiaoHong.sex); //女
    console.log(XiaoMing.sex); //男

    //强行加入一个数组，通过另一个实例push入数组
    console.log("-------数组对象操作修改法----------")
    console.log(XiaoMing.body); //[172,70]
    XiaoHong.body.push('C');
    console.log(XiaoMing.body);  //[172,70,C]
    XiaoHong.body.shift();
    console.log(XiaoMing.body);  //[70,C]

    //难道只有数组会影响？我们试试对象   
    console.log(XiaoMing.hand); //{wristPower : 123 ,handPower : 123}
    XiaoHong.hand.fingerPower = 12; //添加一个对象数据
    console.log(XiaoMing.hand);   //{wristPower : 123 ,handPower : 123, fingerPower :12}
    XiaoHong.hand.wristPower = 0;  //修改一个对象数据
    console.log(XiaoMing.hand);     //{wristPower : 0 ,handPower : 123, fingerPower :12}

    console.log("-------赋值修改法----------")
    // 那我赋值
    console.log(XiaoMing.body); //[70,C]
    XiaoHong.body=['60','B']; 
    console.log(XiaoHong.body); //[60,B]
    console.log(XiaoMing.body); //[70,C]

    console.log(XiaoMing.hand);    //{wristPower : 0 ,handPower : 123, fingerPower :12}
    XiaoHong.hand = {'wristPower' : 234 ,'handPower' : 234};
    console.log(XiaoHong.hand);   // {wristPower : 234 ,handPower : 234}
    console.log(XiaoMing.hand);    //{wristPower : 0 ,handPower : 123, fingerPower :12}

    /**************************上面这堆东东，就是个大坑，总结如下************************************/
    // 首先，父类子类都存在的属性，根据就近原则，继承于子类，所以不会有任何毛病
    // 然后，父类存在子类不存在的属性分为两种。一种为非数组或对象属性，此时直接赋值修改实例对象的该属性，由于prototype原型不让修改，
    // js直接给子类实例添加上该属性的新值；
    // 另一种为数组或对象属性。如果直接赋值，则同上。如果通过push，或直接修改对象内部数据。由于执行了相应的方法，不会在实例下新增属性，
    // 而是在prototype中直接对数组和对象进行修改，从而出现了子类实例互相干扰的情况。

    //终于说道缺点2了。比如我继承了父亲的属性，但是值跟父亲不一样呢？比如，Son和Father都有Name属性，但是值不一样。怎么办。
    // 类式继承显然没法解决这个问题。。。你得在Son里再写一遍this.name = XXX
    // 是不是很麻烦。没事，我们有其他模式供选择

</script>
</html>